<!DOCTYPE html> <!-- -*- html -*- -->
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1, maximum-scale=1">
  <title>The function Ax=b</title>
  <link rel="shortcut icon" href="img/gatech.gif"/>

  
      <link rel="stylesheet" href="css/demo.css?vers=2759ff">
  

  <style>
      

html, body {
    margin:           0;
    height:           100%;
    background-color: white;
    overflow-x:       hidden;
}
.mathbox-wrapper {
    width:       50%;
    padding-top: 50%;
    position:    absolute;
    left:        0;
    top:         50%;
    transform:   translate(0, -50%);
}
.mathbox-wrapper + .mathbox-wrapper {
    left:        50%;
}
.mathbox-wrapper > div {
    position: absolute;
    top:      0;
    left:     0;
    width:    100%;
    height:   100%;
}
.mathbox-label {
    position:  absolute;
    left:      50%;
    top:       10px;
    color:     black;
    opacity:   1.0;
    background-color: rgba(220, 220, 220, .5);
    border:    solid 1px rgba(50, 50, 50, .5);
    padding:   5px;
    transform: translate(-50%, 0);
}
.overlay-text {
    z-index: 1;
}

#inconsistent {
    font-weight:   bold;
    font-size:     120%;
    padding-left:  1em;
    padding-right: 1em;
    color:         var(--palette-red);
    display:       none;
}
#matrix-here {
    display: none;
    text-align: center;
}
.overlay-text > p:last-child {
    text-align: center;
}

  </style>

</head>
<body>
    

<div class="overlay-text">
  <p id="matrix-here"><span id="the-matrix"></span></p>
  <p><span id="the-equation"></span>
      <span id="inconsistent">inconsistent</span></p>
  <p>[Click and drag the heads of x and b]</p>
</div>

<div class="mathbox-wrapper">
    <div id="mathbox1">
        
<div class="mathbox-label">Input</div>

    </div>
</div>
<div class="mathbox-wrapper">
    <div id="mathbox2">
        
<div class="mathbox-label">Output</div>

    </div>
</div>


    
        <script src="js/demo.js?vers=77646a"></script>
    

    <script type="text/javascript">
        "use strict";
        DomReady.ready(function() {

        var basisMode, colBasis, color1, color2, color3, cols, doGrid, i, j, k, l, labeled, lockSolnsKey, matrix, outVec, outVecColor, params, ref, ref1, rows, showSolnsKey, solnspace, solve, surfaceColor, tmp, updateCaption, vecColor, vector;

vector = [-1, 2, 3];

outVec = [0, 0, 0];

colBasis = [];

showSolnsKey = "Show solution set";

lockSolnsKey = "Lock solution set";

solve = null;

solnspace = null;

params = null;

labeled = null;

updateCaption = null;

doGrid = null;

basisMode = null;

matrix = urlParams.get('mat', 'matrix', [[1, -1, 2], [-2, 2, -4]]);

rows = matrix.length;

cols = matrix[0].length;

tmp = [];

for (i = k = 0; k < 3; i = ++k) {
  tmp[i] = [];
  for (j = l = 0; l < 3; j = ++l) {
    tmp[i][j] = (ref = (ref1 = matrix[j]) != null ? ref1[i] : void 0) != null ? ref : 0;
  }
}

matrix = tmp;

vecColor = new Color("green");

outVecColor = new Color("red");

surfaceColor = new Color("violet");

color1 = new Color("orange");

color2 = new Color("brown");

color3 = new Color("pink");

window.demo1 = new (cols === 3 ? Demo : Demo2D)({
  mathbox: {
    element: document.getElementById("mathbox1")
  },
  scaleUI: true
}, function() {
  var Emat, c, clipCube, colors, computeOut, eqnElt, gui, inconsElt, labels, nulBasis, onDrag, r, ref2, ref3, str, tform, tmpVec, vectorEqElt, vectors, view, xBelt;
  window.mathbox1 = this.mathbox;
  this.showSolns = true;
  this.lockSolns = false;
  basisMode = false;
  doGrid = 'disabled';
  switch (this.urlParams.captions) {
    case 'rankthm':
      vector = [0, 0, 0];
      break;
    case 'basis':
      basisMode = true;
      this.showSolns = false;
      this.lockSolns = false;
      doGrid = 'on';
      this.urlParams.axes = 'disabled';
  }
  if (!basisMode) {
    this.showSolns = this.urlParams.get('show', 'bool', true);
    this.lockSolns = this.urlParams.get('lock', 'bool', false);
  }
  this.range = this.urlParams.get('range1', 'float', 5);
  vector = this.urlParams.get('x', 'float[]', vector);
  if (vector[2] == null) {
    vector[2] = 0;
  }
  if (cols === 2) {
    vector[2] = 0;
  }
  this.tMatrix = new THREE.Matrix3();
  this.tMatrix.set(matrix[0][0], matrix[1][0], matrix[2][0], matrix[0][1], matrix[1][1], matrix[2][1], matrix[0][2], matrix[1][2], matrix[2][2]);
  tmpVec = new THREE.Vector3();
  params = {
    Axes: !((ref2 = this.urlParams.axes) === 'off' || ref2 === 'disabled'),
    Homogeneous: (function(_this) {
      return function() {
        vector[0] = vector[1] = vector[2] = 0;
        params[showSolnsKey] = true;
        params[lockSolnsKey] = true;
        solnspace.setVisibility(true);
        return computeOut();
      };
    })(this)
  };
  params[showSolnsKey] = this.showSolns;
  params[lockSolnsKey] = this.lockSolns;
  if (!basisMode) {
    gui = new dat.GUI({
      width: 350
    });
    gui.closed = this.urlParams.closed != null;
    if (this.urlParams.axes !== 'disabled') {
      gui.add(params, 'Axes').onFinishChange((function(_this) {
        return function(val) {
          _this.mathbox.select(".view1-axes").set('visible', val);
          return demo2.mathbox.select(".view2-axes").set('visible', val);
        };
      })(this));
    }
    gui.add(params, showSolnsKey).listen().onFinishChange((function(_this) {
      return function(val) {
        return solnspace.setVisibility(val);
      };
    })(this));
    gui.add(params, lockSolnsKey).listen();
    gui.add(params, 'Homogeneous');
  }
  r = this.range;
  view = this.view({
    name: 'view1',
    viewRange: [[-r, r], [-r, r], [-r, r]].slice(0, cols),
    axisLabels: false,
    grid: doGrid !== 'on'
  });
  this.mathbox.select(".view1-axes").set('visible', params.Axes);
  vectors = [vector];
  colors = [vecColor];
  labels = [];
  if (basisMode) {
    labels.push('[x]_B');
    vectors.push([1, 0, 0]);
    colors.push(color1.arr(.8));
    labels.push('e1');
    vectors.push([0, 1, 0]);
    colors.push(color2.arr(.8));
    labels.push('e2');
    if (cols === 3) {
      vectors.push([0, 0, 1]);
      colors.push(color3.arr(.8));
      labels.push('e3');
    }
  } else {
    labels.push('x');
  }
  labeled = this.labeledVectors(view, {
    vectors: vectors,
    colors: colors,
    labels: labels,
    live: true,
    zeroPoints: true,
    zeroThreshold: 0.1,
    vectorOpts: {
      zIndex: 2
    },
    labelOpts: {
      zIndex: 3
    },
    zeroOpts: {
      zIndex: 3
    }
  });
  clipCube = this.clipCube(view, {
    draw: cols === 3,
    hilite: cols === 3,
    material: new THREE.MeshBasicMaterial({
      color: surfaceColor.three(),
      opacity: 0.5,
      transparent: true,
      visible: false,
      depthWrite: false,
      depthTest: true
    })
  });
  if (doGrid === 'on') {
    this.grid(clipCube.clipped, {
      vectors: [[1, 0, 0], [0, 1, 0], [0, 0, 1]].slice(0, cols),
      live: false,
      lineOpts: {
        color: surfaceColor
      }
    });
  }
  ref3 = this.rowred((function() {
    var len, m, results;
    results = [];
    for (m = 0, len = matrix.length; m < len; m++) {
      c = matrix[m];
      results.push(c.slice());
    }
    return results;
  })(), {
    rows: rows,
    cols: cols
  }), nulBasis = ref3[0], colBasis = ref3[1], Emat = ref3[2], solve = ref3[3];
  this.nulspace = solnspace = this.subspace({
    name: 'nulspace',
    vectors: nulBasis,
    live: false,
    mesh: clipCube.mesh,
    color: surfaceColor
  });
  tform = clipCube.clipped.transform().bind({
    position: (function(_this) {
      return function() {
        return vector;
      };
    })(this)
  });
  solnspace.draw(tform);
  if (solnspace.dim === 3) {
    clipCube.installMesh();
  }
  solnspace.setVisibility(params[showSolnsKey]);
  computeOut = (function(_this) {
    return function() {
      tmpVec.set.apply(tmpVec, vector).applyMatrix3(_this.tMatrix);
      outVec[0] = tmpVec.x;
      outVec[1] = tmpVec.y;
      outVec[2] = tmpVec.z;
      return updateCaption();
    };
  })(this);
  onDrag = (function(_this) {
    return function(vec) {
      if (params[showSolnsKey] && params[lockSolnsKey]) {
        tmpVec.set.apply(tmpVec, vector);
        solnspace.project(vec.sub(tmpVec), vec);
        return vec.add(tmpVec);
      }
    };
  })(this);
  this.draggable(view, {
    points: [vector],
    onDrag: onDrag,
    postDrag: computeOut
  });
  eqnElt = document.getElementById('the-equation');
  inconsElt = document.getElementById('inconsistent');
  switch (this.urlParams.captions) {
    case 'rankthm':
      document.getElementById('matrix-here').style.display = 'block';
      str = this.texMatrix(matrix, {
        rows: rows,
        cols: cols,
        precision: -1
      });
      katex.render('A=' + str, document.getElementById('the-matrix'));
      katex.render("\\text{rank}(A) = " + (cols - solnspace.dim) + " \\qquad\n\\text{dim Nul}(A) = " + solnspace.dim + " \\qquad\n\\#\\text{ columns of } A = " + cols, eqnElt);
      updateCaption = function() {};
      break;
    case 'basis':
      document.querySelector('#mathbox1 .mathbox-label').innerText = 'B-coordinates';
      document.querySelector('#mathbox2 .mathbox-label').innerText = 'Usual coordinates';
      document.querySelector('.overlay-text').innerHTML = "<p><span id=\"x-B-here\"></span></p>\n<p><span id=\"vector-eq-here\"></span></p>";
      xBelt = document.getElementById('x-B-here');
      vectorEqElt = document.getElementById('vector-eq-here');
      updateCaption = (function(_this) {
        return function() {
          var identity, m, ref4;
          str = "\\color{" + (vecColor.str()) + "}{[x]_{\\mathcal B}} = ";
          str += _this.texVector(vector, {
            dim: cols,
            color: vecColor.str()
          });
          str += '=';
          identity = (function() {
            var m, ref4, results;
            results = [];
            for (m = 0, ref4 = cols; 0 <= ref4 ? m < ref4 : m > ref4; 0 <= ref4 ? m++ : m--) {
              results.push((function() {
                var n, ref5, results1;
                results1 = [];
                for (n = 0, ref5 = rows; 0 <= ref5 ? n < ref5 : n > ref5; 0 <= ref5 ? n++ : n--) {
                  results1.push(0);
                }
                return results1;
              })());
            }
            return results;
          })();
          for (i = m = 0, ref4 = Math.min(rows, cols); 0 <= ref4 ? m < ref4 : m > ref4; i = 0 <= ref4 ? ++m : --m) {
            identity[i][i] = 1;
          }
          str += _this.texCombo(identity, vector.slice(0, cols), {
            dim: cols,
            colors: [color1, color2, color3].slice(0, cols),
            coeffColors: vecColor.str()
          });
          katex.render(str, xBelt);
          str = "\\color{" + (outVecColor.str()) + "}{x} =";
          str += _this.texVector(outVec, {
            dim: rows,
            color: outVecColor.str()
          });
          str += '=';
          str += _this.texCombo(matrix.slice(0, cols), vector.slice(0, cols), {
            dim: rows,
            colors: [color1, color2, color3].slice(0, cols),
            coeffColors: vecColor.str()
          });
          return katex.render(str, vectorEqElt);
        };
      })(this);
      break;
    default:
      updateCaption = (function(_this) {
        return function() {
          str = _this.texMatrix(matrix, {
            rows: rows,
            cols: cols,
            precision: -1
          });
          if (labeled.hidden) {
            katex.render(str + ("\\color{" + (vecColor.str()) + "}{x}") + ' = ' + _this.texVector(outVec, {
              color: outVecColor.str(),
              dim: rows
            }), eqnElt);
            return inconsElt.style.display = 'inline';
          } else {
            katex.render(str + _this.texVector(vector, {
              color: vecColor.str(),
              dim: cols
            }) + ' = ' + _this.texVector(outVec, {
              color: outVecColor.str(),
              dim: rows
            }), eqnElt);
            return inconsElt.style.display = 'none';
          }
        };
      })(this);
  }
  return computeOut();
});

window.demo2 = new (rows === 3 ? Demo : Demo2D)({
  mathbox: {
    element: document.getElementById("mathbox2")
  },
  scaleUI: true
}, function() {
  var clipCube, colors, computeIn, diff, labels, onDrag, r, snapThreshold, snapped, subspace, tmpVec, vectors, view;
  window.mathbox2 = this.mathbox;
  this.range = this.urlParams.get('range2', 'float', 10);
  r = this.range;
  view = this.view({
    name: 'view2',
    viewRange: [[-r, r], [-r, r], [-r, r]].slice(0, rows),
    axisLabels: false,
    grid: doGrid !== 'on'
  });
  this.mathbox.select(".view2-axes").set('visible', params.Axes);
  vectors = [outVec];
  colors = [outVecColor];
  labels = [];
  if (basisMode) {
    labels.push('x');
    vectors.push(matrix[0]);
    colors.push(color1.arr(.8));
    labels.push('v1');
    vectors.push(matrix[1]);
    colors.push(color2.arr(.8));
    labels.push('v2');
    if (cols === 3) {
      vectors.push(matrix[2]);
      colors.push(color3.arr(.8));
      labels.push('v3');
    }
  } else {
    labels.push('b');
  }
  this.labeledVectors(view, {
    vectors: vectors,
    colors: colors,
    labels: labels,
    live: true,
    zeroPoints: true,
    zeroThreshold: 0.3,
    vectorOpts: {
      zIndex: 2
    },
    labelOpts: {
      zIndex: 3
    },
    zeroOpts: {
      zIndex: 3
    }
  });
  clipCube = this.clipCube(view, {
    draw: rows === 3,
    hilite: rows === 3,
    material: new THREE.MeshBasicMaterial({
      color: surfaceColor.three(),
      opacity: 0.5,
      transparent: true,
      visible: false,
      depthWrite: false,
      depthTest: true
    })
  });
  if (doGrid === 'on') {
    this.grid(clipCube.clipped, {
      vectors: matrix.slice(0, rows),
      live: false,
      lineOpts: {
        color: surfaceColor
      }
    });
  }
  subspace = this.subspace({
    name: 'colspace',
    vectors: colBasis,
    live: false,
    noPlane: basisMode && rows === 2,
    color: surfaceColor
  });
  subspace.draw(clipCube.clipped);
  if (subspace.dim === 3) {
    clipCube.installMesh();
    clipCube.mesh.material.visible = true;
  }
  snapThreshold = 1.0 * 10.0 / this.range;
  snapped = new THREE.Vector3();
  diff = new THREE.Vector3();
  onDrag = (function(_this) {
    return function(vec) {
      subspace.project(vec, snapped);
      diff.copy(vec).sub(snapped);
      if (diff.lengthSq() <= snapThreshold || basisMode) {
        return vec.copy(snapped);
      }
    };
  })(this);
  computeIn = function() {
    var inVec;
    inVec = solve(outVec);
    if (inVec != null) {
      if (inVec[2] == null) {
        inVec[2] = 0;
      }
      tmpVec.set(vector[0] - inVec[0], vector[1] - inVec[1], vector[2] - inVec[2]);
      solnspace.project(tmpVec, tmpVec);
      vector[0] = tmpVec.x + inVec[0];
      vector[1] = tmpVec.y + inVec[1];
      vector[2] = tmpVec.z + inVec[2];
      demo1.nulspace.setVisibility(params[showSolnsKey]);
      labeled.show();
    } else {
      demo1.nulspace.setVisibility(false);
      labeled.hide();
    }
    return updateCaption();
  };
  tmpVec = new THREE.Vector3();
  return this.draggable(view, {
    points: [outVec],
    onDrag: onDrag,
    postDrag: computeIn
  });
});

groupControls(demo1, demo2);


        });
    </script>
</body>
</html>

